package com.qianfeng.smartdevice.service.impl;

import com.github.pagehelper.PageInfo;
import com.qianfeng.smartdevice.cache.CategoriesCache;
import com.qianfeng.smartdevice.constans.ResultCode;
import com.qianfeng.smartdevice.event.CategoryCacheChangeEvent;
import com.qianfeng.smartdevice.exceptions.AddDataException;
import com.qianfeng.smartdevice.mapper.CategoryMapper;
import com.qianfeng.smartdevice.pojo.Categories;
import com.qianfeng.smartdevice.service.ICategoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.stream.Collectors;

@Service
@Transactional
public class CategoryServiceImpl implements ICategoryService {
    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private CategoriesCache categoriesCache;
    @Autowired
    private ApplicationContext context;
    @Autowired
    private CategoryCacheChangeEvent event;

    @Override
    @Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
    public PageInfo<Categories> findAllCategoriesByPage(int page, int limit, String categoryname, Long status) {
        // PageHelper.startPage(page, limit);
        PageInfo<Categories> pageInfo = null;
        // List<Categories> categoriesList = categoryMapper.findAllCategories();
        List<Categories> categoriesList = categoriesCache.getAllData();//缓存中如果没有数据,我们不查询数据库,因为缓存中没有基本就代表了数据库中也没有
        //根据条件切割上面的集合
        //集合现在有 19 条数据, 我们要第2页,要 10 条
//        if (categoriesList.size() <= page * limit) {
//            //当我们要的数据不是第一页的时候,会出现将第一页的数据也返回,因为会出现超过一页,但是不能满满的刚好到第二或者更多页
//            pageInfo = new PageInfo<>(categoriesList);
//        }else{
//            //裁剪集合
//            List<Categories> subList = categoriesList.subList((page - 1) * limit, page * limit);
//            pageInfo = new PageInfo<>(subList);
//        }
        // int start_index = 0;

        //遍历集合,判断每条数据是不是符合我们的查询条件
        List<Categories> realCategoriesList = categoriesList.stream().filter(categories -> {
            boolean isFetchName = true;
            boolean isFetchStatus = true;
            String categoryname1 = categories.getCategoryname(); //获取对象上面的分类名,用于和名字进行判断的
            Long status1 = categories.getStatus();//获取对象上面的状态
            if (!StringUtils.isEmpty(categoryname)) {
                //代表传递了分类的名字
                isFetchName = categoryname1.contains(categoryname);//判断分类的名字中是否包含传递的名字
            }
//
            if (status!=null&&-100!=status){//如果传递了状态并且不是默认的无状态
                //判断对象的状态和查询的状态是否一致
                isFetchStatus=status==status1;
            }



            return isFetchName && isFetchStatus;//stream 的 filter 要求返回一个 boolean,我们返回的就是是否匹配传递的用户名和状态条件

        }).collect(Collectors.toList());


        //=================华丽的分割线,准备切割符合条件的集合===================
        int last_index = limit;//为了防止第一页没有数据,所以默认就写 limit

        if (page * limit >= realCategoriesList.size()) { //为了防止出现在切割集合的时候出现数组越界
            last_index = realCategoriesList.size();//如果超出了总长度,则最后的一个切割下标就是总长度
        }else{
            last_index=page * limit;//在不超出范围的情况下就是当前页*每页的数量
        }

        if ((page - 1) * limit >= realCategoriesList.size()) {
            //起点超出查询范围了,直接返回空数据
            pageInfo = new PageInfo<>();
            return pageInfo;
        }
        //切割集合,上面的代码都是怕越界而做的判断
        List<Categories> subList = realCategoriesList.subList((page - 1) * limit , last_index);
        pageInfo = new PageInfo<>(subList);
        pageInfo.setTotal(realCategoriesList.size());//设置总长度为符合条件的集合的长度
        return pageInfo;
    }


    @Override
    public void addCategory(Categories categories) {
        if (categories == null || categories.isNull()) {
            throw new AddDataException("数据不能为空", ResultCode.NULL_DATA);
        }
        categoryMapper.addCategoy(categories);
        //更新缓存,如果在这里直接操作缓存,万一出现异常,会导致事务回滚,添加失败,更新缓存应该要影响添加数据吗?
        //经过分析发现,即便是更新缓存失败,也不应该回滚数据,也就是说这是两个完全独立的操作
        //Event 事件,相当于拿着喇叭喊了一嗓子,等着听到的人去执行
        context.publishEvent(event);//发送事件,解耦
    }
}